﻿using DataModels.Dto;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;

public class ExceptionHandlerService
{
    private readonly ILogger<ExceptionHandlerService> _logger;
    private readonly IHttpContextAccessor _httpContextAccessor; 

    public ExceptionHandlerService(
        ILogger<ExceptionHandlerService> logger,
        IHttpContextAccessor httpContextAccessor) 
    {
        _logger = logger;
        _httpContextAccessor = httpContextAccessor;
    }

    // 处理异常并生成响应的核心方法
    public async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        // 记录详细异常日志
        _logger.LogError(exception, "全局异常捕获");

        // 创建统一的错误响应
        var responseModel = CreateErrorResponse(exception);

        // 设置HTTP状态码和响应内容
        context.Response.StatusCode = responseModel.Code;
        context.Response.ContentType = "application/json";

        // 使用安全的JSON序列化选项（避免循环引用）
        var jsonOptions = new JsonSerializerOptions
        {
            ReferenceHandler = ReferenceHandler.IgnoreCycles,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        await context.Response.WriteAsync(
            JsonSerializer.Serialize(responseModel, jsonOptions)
        );
    }

    // 根据异常类型创建不同的响应模型
    private ResponseModel CreateErrorResponse(Exception exception)
    {
        var response = new ResponseModel();

        switch (exception)
        {
            // 处理JSON序列化错误（服务端问题）
            case JsonException jsonException when IsSerializationError(jsonException):
                response.Code = StatusCodes.Status500InternalServerError;
                response.Message = "服务器数据处理错误: " + jsonException.Message;
                break;

            // 处理JSON解析错误（客户端请求格式问题）
            case JsonException jsonException:
                response.Code = StatusCodes.Status400BadRequest;
                response.Message = "请求格式错误: " + jsonException.Message;
                break;

            case ArgumentNullException:
                response.Code = StatusCodes.Status400BadRequest;
                response.Message = "参数不能为空";
                break;

            case UnauthorizedAccessException:
                response.Code = StatusCodes.Status401Unauthorized;
                response.Message = "未授权访问";
                break;

            case KeyNotFoundException:
                response.Code = StatusCodes.Status404NotFound;
                response.Message = "资源不存在";
                break;

            default:
                response.Code = StatusCodes.Status500InternalServerError;
                response.Message = "服务器内部错误，请稍后重试";
                break;
        }

        return response;
    }
    // 判断是否为序列化错误（而非解析错误）
    private bool IsSerializationError(JsonException exception)
    {
        // 检查异常堆栈中是否包含序列化相关的调用
        bool IsInSerializationStack(StackTrace stackTrace)
        {
            foreach (var frame in stackTrace.GetFrames() ?? Array.Empty<StackFrame>())
            {
                var method = frame.GetMethod();
                if (method != null)
                {
                    // 检查是否在序列化输出格式化器中
                    if (method.DeclaringType?.FullName?.Contains("System.Text.Json.Serialization.Converters") == true ||
                        method.DeclaringType?.FullName?.Contains("System.Text.Json.Serialization.Metadata") == true ||
                        method.DeclaringType?.FullName?.Contains("Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter") == true)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        // 1. 检查典型的循环引用错误消息
        if (exception.Message.Contains("A possible object cycle was detected"))
        {
            return true;
        }

        // 2. 检查异常发生的上下文（通过HttpContext判断）
        var httpContext = _httpContextAccessor?.HttpContext;
        if (httpContext != null)
        {
            // 如果是响应阶段（输出格式化）
            if (httpContext.Response.HasStarted)
            {
                return true;
            }

            // 如果是请求阶段（输入格式化）
            if (httpContext.Features.Get<IEndpointFeature>()?.Endpoint != null &&
                !httpContext.Response.HasStarted)
            {
                return false;
            }
        }

        // 3. 分析异常堆栈
        var stackTrace = new StackTrace(exception, true);
        return IsInSerializationStack(stackTrace);
    }
}